﻿using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static WCAD.Jigs;

namespace WCAD
{
    public static class UmUserMethod
    {
        /// <summary>
        /// 返回指定类型的List<T>
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="message"></param>
        /// <returns></returns>
        public static bool SelectEntities<T>(out List<T> result, string message = "选择图形") where T : Entity
        {
            result = new List<T>();
            Editor editor = Application.DocumentManager.MdiActiveDocument.Editor;
            PromptSelectionOptions pso = new PromptSelectionOptions();
            pso.MessageForAdding = "\n" + message;
            PromptSelectionResult psr = editor.GetSelection(pso);
            if (psr.Status == PromptStatus.OK)
            {
                ObjectId[] objectids = psr.Value.GetObjectIds();
                Database database = HostApplicationServices.WorkingDatabase;
                using (Transaction tran = database.TransactionManager.StartTransaction())
                {
                    foreach (var item in objectids)
                    {
                        Entity entity = (Entity)item.GetObject(OpenMode.ForRead);
                        if (entity is T)
                        {
                            result.Add(entity as T);
                        }

                    }
                }
            }
            return result.Count() > 0;
        }
        public static bool SelectCrossingWindow<T>(Point3d p1,Point3d p2, out List<T> result) where T : Entity
        {
            result = new List<T>();
            Editor editor = Application.DocumentManager.MdiActiveDocument.Editor;
            PromptSelectionResult psr = editor.SelectCrossingWindow(p1,p2);
            if (psr.Status == PromptStatus.OK)
            {
                ObjectId[] objectids = psr.Value.GetObjectIds();
                Database database = HostApplicationServices.WorkingDatabase;
                using (Transaction tran = database.TransactionManager.StartTransaction())
                {
                    foreach (var item in objectids)
                    {
                        Entity entity = (Entity)item.GetObject(OpenMode.ForRead);
                        if (entity is T)
                        {
                            result.Add(entity as T);
                        }

                    }
                }
            }
            return result.Count() > 0;
        }
        public static bool SelectFence<T>(List<Point3d> points, out List<T> result) where T : Entity
        {
            result = new List<T>();
            Editor editor = Application.DocumentManager.MdiActiveDocument.Editor;
            Point3dCollection pos = new Point3dCollection();
            points.ForEach(x => pos.Add(x));
            PromptSelectionResult psr = editor.SelectFence(pos);
            if (psr.Status == PromptStatus.OK)
            {
                ObjectId[] objectids = psr.Value.GetObjectIds();
                Database database = HostApplicationServices.WorkingDatabase;
                using (Transaction tran = database.TransactionManager.StartTransaction())
                {
                    foreach (var item in objectids)
                    {
                        Entity entity = (Entity)item.GetObject(OpenMode.ForRead);
                        if (entity is T)
                        {
                            result.Add(entity as T);
                        }

                    }
                }
            }
            return result.Count() > 0;
        }

        /// <summary>
        /// 获得所有指定类型Entity
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static List<T> SelectAllEntities<T>() where T : Entity
        {
            List<T> result = new List<T>();
            Database db = HostApplicationServices.WorkingDatabase;
            using (Transaction tran = db.TransactionManager.StartTransaction())
            {
                BlockTable bt = (BlockTable)db.BlockTableId.GetObject(OpenMode.ForRead);
                BlockTableRecord btr = (BlockTableRecord)bt[BlockTableRecord.ModelSpace].GetObject(OpenMode.ForRead);
                foreach (ObjectId item in btr)
                {
                    Entity entity = (Entity)item.GetObject(OpenMode.ForRead);
                    if (entity is T)
                    {
                        result.Add(entity as T);
                    }
                }
            }

            return result;
        }

        /// <summary>
        /// 获取一个Entity
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="message">提示词</param>
        /// <param name="entity">传出的Entity</param>
        /// <param name="point">点击坐标</param>
        /// <returns></returns>
        public static bool GetEntity<T>(out T entity, out Point3d point, string message = "") where T : Entity
        {
            entity = null;
            point = new Point3d();
            Editor editor = Application.DocumentManager.MdiActiveDocument.Editor;
            PromptEntityResult per = editor.GetEntity("\n" + message);
            if (per.Status == PromptStatus.OK)
            {
                ObjectId objectid = per.ObjectId;
                point = per.PickedPoint;
                Database database = HostApplicationServices.WorkingDatabase;
                using (Transaction tran = database.TransactionManager.StartTransaction())
                {
                    entity = objectid.GetObject(OpenMode.ForRead) as T;
                    if (entity == null) return false;
                    else return true;
                }
            }
            return false;
        }

        /// <summary>
        /// 获取一个Entity
        /// </summary>
        /// <param name="message">提示词</param>
        /// <param name="entity">传出的Entity</param>
        /// <returns></returns>
        public static bool GetEntity<T>(out T entity, string message = "选择图形") where T : Entity
        {
            return GetEntity(out entity, out Point3d point, message);
        }
        /// <summary>
        /// 获取块中的一个Entity
        /// </summary>
        /// <param name="message"></param>
        /// <param name="entity"></param>
        /// <returns></returns>
        public static bool GetNestedEntity<T>(out T entity, string message = "") where T : Entity
        {
            entity = null;
            Editor editor = Application.DocumentManager.MdiActiveDocument.Editor;
            PromptNestedEntityResult pner = editor.GetNestedEntity("\n" + message);
            if (pner.Status == PromptStatus.OK)
            {
                Database db = HostApplicationServices.WorkingDatabase;
                using (Transaction tran = db.TransactionManager.StartTransaction())
                {
                    entity = (T)pner.ObjectId.GetObject(OpenMode.ForRead);
                    return true;
                }
            }
            return false;
        }
        

        /// <summary>
        /// 获取用户输入文字
        /// </summary>
        /// <param name="message">提示词</param>
        /// <param name="str">传出的文字</param>
        /// <returns></returns>
        public static bool GetString(out string str, string message = "")
        {
            str = "";
            Editor editor = Application.DocumentManager.MdiActiveDocument.Editor;
            PromptResult pr = editor.GetString(message);
            if (pr.Status == PromptStatus.OK)
            {
                str = pr.StringResult;
                return true;
            }
            return false;
        }

        /// <summary>
        /// 获取用户输入整数
        /// </summary>
        /// <param name="message">提示词</param>
        /// <param name="num">传出的整数</param>
        /// <returns></returns>
        public static bool GetInt(out int num, string message = "", int value = 0)
        {
            num = 0;
            Editor editor = Application.DocumentManager.MdiActiveDocument.Editor;
            PromptIntegerOptions pio = new PromptIntegerOptions(message);
            pio.DefaultValue = value;
            PromptIntegerResult pir = editor.GetInteger(pio);
            if (pir.Status == PromptStatus.OK)
            {
                num = pir.Value;
                return true;
            }
            return false;
        }

        /// <summary>
        /// 获取用户输入小数
        /// </summary>
        /// <param name="message">提示词</param>
        /// <param name="d">传出的小数</param>
        /// <returns></returns>
        public static bool GetDouble(out double d, string message = "请输入数字",double value=0)
        {
            d = 0;
            Editor editor = Application.DocumentManager.MdiActiveDocument.Editor;
            PromptDoubleOptions pdo = new PromptDoubleOptions(message);
            pdo.DefaultValue = value;
            PromptDoubleResult pdr = editor.GetDouble(pdo);
            if (pdr.Status == PromptStatus.OK)
            {
                d = pdr.Value;
                return true;
            }
            return false;
        }
        /// <summary>
        /// 获取一个点
        /// </summary>
        /// <param name="message">提示词</param>
        /// <param name="point"></param>
        /// <returns></returns>
        public static bool GetPoint(out Point3d point, string message = "选择点",Point3d? p=null)
        {
            point = Point3d.Origin;
            Editor editor = Application.DocumentManager.MdiActiveDocument.Editor;
            PromptPointOptions ppo = new PromptPointOptions(message);
            if (p != null)
            {
                ppo.BasePoint=p.Value;
                ppo.UseBasePoint= true;
            }
            PromptPointResult ppr = editor.GetPoint(ppo);
            if (ppr.Status == PromptStatus.OK)
            {
                point = ppr.Value;
                return true;
            }
            return false;
        }
        public static bool GetCorner(Point3d basePoint,out Point3d point, string message = "")
        {
            point = Point3d.Origin;
            PromptCornerOptions pco = new PromptCornerOptions(message, basePoint);
            pco.UseDashedLine = true;
            Editor editor = Application.DocumentManager.MdiActiveDocument.Editor;
            PromptPointResult ppr = editor.GetCorner(pco);
            if (ppr.Status == PromptStatus.OK)
            {
                point=ppr.Value;
                if (point.DistanceTo(basePoint) > 0) return true;
                else return false;
            }
            return false;
        }
        public static bool GetKeywords(out string result,List<string> strs, string message = "")
        {
            result = "";
            PromptKeywordOptions pko = new PromptKeywordOptions(message);
            foreach (var item in strs)
            {
                if(item.Contains("(")&& item.Contains(")"))
                {
                    string str = item.Split('(')[1].Replace(")", "");
                    pko.Keywords.Add(str, str,item);
                }
            }
            Editor editor = Application.DocumentManager.MdiActiveDocument.Editor;
            PromptResult pr = editor.GetKeywords(pko);
            if (pr.Status == PromptStatus.OK)
            {
                result = pr.StringResult;
                return true;
            }
            return false;
        }
        public static List<Point3d> GetPoints()
        {
            var r1 = Application.DocumentManager.MdiActiveDocument.Editor.GetSelection();
            var a = r1.Value[0];
            List<Point3d> points = new List<Point3d>();
            if (a is CrossingOrWindowSelectedObject c)
            {
                foreach (PickPointDescriptor item in c.GetPickPoints())
                {
                    points.Add(item.PointOnLine);
                }
            }
            return points;
        }
        public static List<T> DrawOrderFull<T>() where T : Entity
        {
            Database db = HostApplicationServices.WorkingDatabase;
            List<T> entities = new List<T>();
            using (Transaction trans = db.TransactionManager.StartTransaction())
            {
                BlockTable bt = (BlockTable)db.BlockTableId.GetObject(OpenMode.ForRead);
                BlockTableRecord btr = (BlockTableRecord)bt[BlockTableRecord.ModelSpace].GetObject(OpenMode.ForRead);
                DrawOrderTable orderTable = btr.DrawOrderTableId.GetObject(OpenMode.ForRead) as DrawOrderTable;
                ObjectIdCollection ids = orderTable.GetFullDrawOrder(new byte());
                foreach (var item in ids)
                {
                    ObjectId id = (ObjectId)item;
                    Entity entity = id.GetObject(OpenMode.ForRead) as Entity;
                    if (entity is T)
                    {
                        entities.Add(entity as T);
                    }
                }
            }
            return entities;
        }
        public static void SetImpliedSelection(List<DBObject> dbs)
        {
            SelectionSet selectionSet = SelectionSet.FromObjectIds(dbs.Select(x => x.ObjectId).ToArray());
            Application.DocumentManager.MdiActiveDocument.Editor.SetImpliedSelection(selectionSet);
        }
        public static bool CreatPolyline(out Polyline polyline,bool b=false)
        {
            polyline = new Polyline();

            if (!UmUserMethod.GetPoint(out Point3d point, "选择起点")) return false;
            polyline.AddVertexAt(0, point.ToPoint2d(), 0, 0, 0);
            JigPromptPointOptions jppo = new JigPromptPointOptions("点击下一个点,按Esc结束绘制\n");
            while (true)
            {
                Line line = new Line(polyline.EndPoint, polyline.EndPoint);
                Polyline pl = polyline.KeLong();
                JigJig jig = new JigJig(point, (p, e1, e2) =>
                {
                    line.EndPoint = p;
                    e2.Add(pl);
                    e2.Add(line);
                }, jppo);
                if (WCAD.Ed.Drag(jig).Status == PromptStatus.OK)
                {

                    polyline.AddVertexAt(polyline.NumberOfVertices, line.EndPoint.ToPoint2d(), 0, 0, 0);
                }
                else
                {
                    break;
                }
            }
            if (b && polyline.Closed == false && polyline.NumberOfVertices > 1)
            {
                polyline.Closed= true;
            }
            return polyline.NumberOfVertices > 1;
        }
    }
}
